"""Support for Ebusd daemon for communication with eBUS heating systems."""
from datetime import timedelta
import logging
import socket

import voluptuous as vol

from homeassistant.const import (
    CONF_NAME, CONF_HOST, CONF_PORT, CONF_MONITORED_CONDITIONS)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.discovery import load_platform
from homeassistant.util import Throttle

from .const import (DOMAIN, SENSOR_TYPES)

_LOGGER = logging.getLogger(__name__)

DEFAULT_NAME = 'ebusd'
DEFAULT_PORT = 8888
CONF_CIRCUIT = 'circuit'
CACHE_TTL = 900
SERVICE_EBUSD_WRITE = 'ebusd_write'

MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=15)

CONFIG_SCHEMA = vol.Schema({
    DOMAIN: vol.Schema({
        vol.Required(CONF_CIRCUIT): cv.string,
        vol.Required(CONF_HOST): cv.string,
        vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
        vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
        vol.Optional(CONF_MONITORED_CONDITIONS, default=[]): vol.All(
            cv.ensure_list, [vol.In(SENSOR_TYPES['700'])])
    })
}, extra=vol.ALLOW_EXTRA)


def setup(hass, config):
    """Set up the eBusd component."""
    conf = config[DOMAIN]
    name = conf[CONF_NAME]
    circuit = conf[CONF_CIRCUIT]
    monitored_conditions = conf.get(CONF_MONITORED_CONDITIONS)
    server_address = (
        conf.get(CONF_HOST), conf.get(CONF_PORT))

    try:
        _LOGGER.debug("Ebusd component setup started")
        import ebusdpy
        ebusdpy.init(server_address)
        hass.data[DOMAIN] = EbusdData(server_address, circuit)

        sensor_config = {
            CONF_MONITORED_CONDITIONS: monitored_conditions,
            'client_name': name,
            'sensor_types': SENSOR_TYPES[circuit]
        }
        load_platform(hass, 'sensor', DOMAIN, sensor_config, config)

        hass.services.register(
            DOMAIN, SERVICE_EBUSD_WRITE, hass.data[DOMAIN].write)

        _LOGGER.debug("Ebusd component setup completed")
        return True
    except (socket.timeout, socket.error):
        return False


class EbusdData:
    """Get the latest data from Ebusd."""

    def __init__(self, address, circuit):
        """Initialize the data object."""
        self._circuit = circuit
        self._address = address
        self.value = {}

    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    def update(self, name, stype):
        """Call the Ebusd API to update the data."""
        import ebusdpy

        try:
            _LOGGER.debug("Opening socket to ebusd %s", name)
            command_result = ebusdpy.read(
                self._address, self._circuit, name, stype, CACHE_TTL)
            if command_result is not None:
                if 'ERR:' in command_result:
                    _LOGGER.warning(command_result)
                else:
                    self.value[name] = command_result
        except RuntimeError as err:
            _LOGGER.error(err)
            raise RuntimeError(err)

    def write(self, call):
        """Call write methon on ebusd."""
        import ebusdpy
        name = call.data.get('name')
        value = call.data.get('value')

        try:
            _LOGGER.debug("Opening socket to ebusd %s", name)
            command_result = ebusdpy.write(
                self._address, self._circuit, name, value)
            if command_result is not None:
                if 'done' not in command_result:
                    _LOGGER.warning('Write command failed: %s', name)
        except RuntimeError as err:
            _LOGGER.error(err)
